﻿using Microsoft.VisualStudio.Debugger.Interop;
using Red.CommUtils;
using Red.Scripts.Debugger.Defines;

namespace Red.Scripts.Debugger.Remote.Debugger.ExpressionEvaluation
{
    internal class Expression : IDebugExpression2
    {
        #region Private Data

        private string _expression;
        private IChannel _channel;
        private Thread _thread;
        private int _stackId;

        #endregion Private Data
        #region C-Tor

        public Expression( StackFrame frame, string expression )
        {
            _expression = expression;
            _channel = frame.Parent.Parent.Channel;
            _thread = frame.Parent;
            _stackId = frame.Frame.id;
        }

        #endregion C-Tor

        #region Event Handlers

        void MessageRecieved( comm.Message message, IResponse responseGateway )
        {
            switch ( message.GetID() )
            {
                case comm.EMessageID.ScriptLocals:
                    {
                        comm.ScriptLocals locals = (comm.ScriptLocals)message;

                        if ( locals.locals[ 0 ].path == _expression )
                        {
                            Property property = new Property( locals.locals[ 0 ], _channel, _thread.Data.id, _stackId );
                            _thread.Parent.Postman.SendExpressionEvaluationCompleted( this, property, _thread.Parent, _thread );

                            _channel.UnregisterListener( MessageRecieved );
                        }
                    }
                    break;
            }
        }

        #endregion Event Handlers

        #region IDebugExpression2

        int IDebugExpression2.EvaluateAsync( enum_EVALFLAGS dwFlags, IDebugEventCallback2 pExprCallback )
        {
            _channel.RegisterListener( MessageRecieved );

            comm.ScriptLocalsRequest request = new comm.ScriptLocalsRequest()
            {
                path = _expression,
                threadId = _thread.Data.id,
                stackId = _stackId,
                children = false
            };

            _channel.Send( request );

            return Constants.S_OK;
        }

        int IDebugExpression2.EvaluateSync( enum_EVALFLAGS dwFlags, uint dwTimeout, IDebugEventCallback2 pExprCallback, out IDebugProperty2 ppResult )
        {
            comm.ScriptLocalsRequest request = new comm.ScriptLocalsRequest()
            {
                path = _expression,
                threadId = _thread.Data.id,
                stackId = _stackId,
                children = false
            };

            comm.Message response = _channel.SendAndWait( request, (int)dwTimeout );

            if ( response == null )
            {
                ppResult = null;
                return Constants.E_FAIL;
            }

            comm.ScriptLocals locals = (comm.ScriptLocals)response;

            if ( locals.locals.Count == 0 )
            {
                ppResult = null;
                return Constants.E_FAIL;
            }

            ppResult = new Property( locals.locals[ 0 ], _channel, _thread.Data.id, _stackId ) { Name = _expression };
            return Constants.S_OK;
        }

        int IDebugExpression2.Abort()
        {
            return Constants.E_NOTIMPL;
        }

        #endregion IDebugExpression2
    }
}
